// **************************************************************
//COPYRITE (c) 2010,ISN State Key Library
//All rights reserved
//                              
//IP LIB INDEX : 
//IP Name      : 
//File Name    :flow_ctrl.v
//Module Name  :FLOW_CTRL
//Full Name    :
//Author       :
//Email        :                        
//Data         :
//Version      :V0.1
//Abstract     :
//Called by    :
//Modification history:2010.12.1 zww  ??????????? out_port_num
//Modification history:2011.7.26 zww  ??????????????????????????????????????????????????????????? frame_length                  
//**********************************************                

//**********************
//  DEFINE MODULE PORT//
//**********************

/*
���ڽ����ģ�������֡���ж����������Ƿ�����������֡ͨ����
���ȶԽ�������ģ�������֡�����жϣ�������ұ����ҳɹ������������ض���Ҫ���صĶ˿ڣ��������롣
��ȡ��ת����ģ�������Ŀ�Ķ˿�id����ȡ��ǰram1��ram2�Ĳ�����
�Ƚϼ��㵱ǰ�˿������Ƿ������ֵ��
�����ǰ����������֧����һ������֡�Ľ��룬��������ʧ�ܵ�״̬��Ϣ��Ȼ�������

��ϸ�������̣�
Frame_length_en��Ч����frame_length�洢���ڲ�reg�У���frame_length_enҲ�洢�������ڲ��������źš�
��ַʹ�ܣ�addr_en�������ҳɹ�(look_fail)����Դ�˿�(out_port_num�жϾ�ʱ���洢Ŀ�Ķ˿�(addr_reg)�����Ŀ�Ķ˿�id����des_node_id��ͬʱ������ڶ�ram2���в�����״̬��busy���Ͷ�ram2���в����ĵ�ַ��
��frame_length_en_ff1��Ч�����ұ�֤������Ҫ���صĶ˿ڣ���Ŀ�Ķ˿ڵ�ַ�����ram2ģ�飨addr_ram����
ͬʱ����rw_en��������дʹ���źţ�rw_en��
rw_en�ӳ�3�����ں󣬶�ȡ����ram2�Ķ�Ӧ�˿�������Ϣ��
��ǰ�˿����عرգ�������سɹ�������������Ϣ��ram2 ��
��ǰ�˿����ؿ�������������������ֵ��������سɹ���������������Ϊ��ǰ����������ȥframe_length��
���򣬸�������ʧ�ܣ����ص�ǰ��������Ϣ��ram2������������
rw_en�ӳ�4�����ں󣬸�����ram2���ж�д��write_read�źţ�����result_enʹ���źš����result��
����busy�Ͷ�ram2�����ĵ�ַΪ0��

PS��ͨ�������ķ�ʽȥ"Ԥ��"���ұ��Ľ������ʱ�䣡

Q���᲻����������"���������"----������Ҫ����һ��"�֡"ʱ�������سɹ���
*/

`include    "top_define.v"
//`define     TIMEDELAY                   1  
`define     TIMEDELAY                   0  
`define     TOKEN_LOW_LIMIT            1522  

module  flow_ctrl_emac    (
                    //connect with receive_scheduler
                    clk                ,
                    rst_n              ,
                    //��ֱ�Ӻ��ⲿ������
                    addr               , //����֡Ҫ������outport
                    addr_en            , //��ַʹ��
                    look_fail          , //ת��������ʧ��ָ��
 		            out_port_num       , //����֡����Դ�˿ڣ�����ض��˿���Դ������֡�������أ���addr��frame_length���п������ã�
                                            //��Ϊ2'b01ʱһ�����1����ʾ����Ҫ���أ�
                                            //Ϊ2'b01ʱ�ŻỺ��addr��ͬʱaddr_reg��ַ�Ż����addr_ram����ͬʱҲ�����rw_en�źš�
                    result             , //���ؽ����1�ɹ���0ʧ��
                    result_en          , //���ؽ��ʹ��
                    des_node_id        , //����֡Ҫ������outport����"addr"�����ظ�����˿սӣ�
					frame_length       , //֡����
					frame_length_en	   , //֡����ʹ�ܣ�ע���frame_length_en����֮������Ͽ�ʼrw_en�ļ�����
					do_not_flow_ctrl   , //�������

                    //connect with port B of flow_ram_2 
                    token_data_out     , //��RAM2����
                    token_data_in      , //��RAM2����
                    addr_ram           , //��RAM2����
                    read_write         , //��RAM2����

                    //connect with input_token
                    busy               , //�����input_token����ʾ���ڲ���
                    operate_addr      	 //�����input_token����ʾ���ڲ����ĵ�ַ				
					
                    );

//**********************
//  connect with receive_scheduler and emac_counter module //
//********************** 

input          clk             ;
input          rst_n           ;
//connect with     cam_top
input          look_fail       ;
input  [7 :0]  addr            ;
input          addr_en         ;
input  [1 :0]  out_port_num    ;  //zww 2010.12.1 
output         result          ;
output         result_en       ;
output [7 :0]  des_node_id     ;
input  [10:0]  frame_length    ; //2011.7.26 zww 
input          frame_length_en ; //2014.7.31 2.0 myb
input          do_not_flow_ctrl;
//**********************
//  connect with port B of flow_ram_2 //
//********************** 
(*mark_debug = "true"*)input  [31:0]  token_data_out  ;
(*mark_debug = "true"*)output [31:0]  token_data_in   ; 
(*mark_debug = "true"*)output [7 :0]  addr_ram        ;
(*mark_debug = "true"*)output         read_write      ; 
//**********************
//  connect with input_token.v //
//********************** 
output         busy            ;
output[7:0]    operate_addr    ;


//**********************
//DIFINE ATRRIBUTE//
//**********************
//REGS
reg    [31:0]  token_data_in    ;
reg    [7 :0]  addr_ram         ;
reg            read_write       ;
reg            result           ;
reg            result_en        ;
reg    [7 :0]  des_node_id      ;

//internal signal register
// reg            clk_token       ;//   the clock cycle of generating  token
reg    [10:0]  frame_length_reg;     //2011.7.26 zww 

reg            busy            ;
reg    [7 :0]  operate_addr    ;

reg            rw_en           ;
reg            rw_en_ff1       ;
reg            rw_en_ff2       ; 
reg            rw_en_ff3       ;
reg            rw_en_ff4       ;

reg            rw_en_h         ; //��"��������"ʱ�������ź�
reg            rw_en_h_ff1     ;
reg            rw_en_h_ff2     ;
reg            rw_en_h_ff3     ;
reg            rw_en_h_ff4     ;
reg            flow_result     ;
reg      [7 :0]  addr_reg      ; 
parameter      flow_success = 1'b1  ;
parameter      flow_fail    = 1'b0  ;

reg frame_length_en_ff1			;

//**********************
//MAIN CODE//
//**********************



//*************************************************************************************************************
//��֡���ź���Чʱ��֡������һ��
always @(negedge rst_n or posedge clk)
	begin
		if(!rst_n)
		frame_length_reg<= 11'd0;
		else if (frame_length_en)
			frame_length_reg<= frame_length;
		else
			frame_length_reg<= frame_length_reg;
	end
//*************************************************************************************************************
//֡����Ч�źŴ�һ��
always @(negedge rst_n or posedge clk) //��֡��ʹ���źŴ洢��reg��
	begin
		if(!rst_n)
			frame_length_en_ff1<= 1'd0;
		else
			frame_length_en_ff1<= frame_length_en;
	end
//*************************************************************************************************************
//��ַ��Ч���Ҳ��Ҳ�ʧ��ʱ�ѵ�ַ����һ��
always @(negedge rst_n or posedge clk) //�ڵ�ַʹ���ź������Ҳ���ɹ��������ض��˿������£���Ŀ�Ķ˿�д���ڲ�reg
	begin
		if(!rst_n)
		addr_reg<= 8'd0;
		else if (addr_en&&!look_fail&&out_port_num==2'b01)
			addr_reg<= addr;
		else
			addr_reg<= addr_reg;
	end
//֡����Чʱ�ѵ�ַ����RAM
always @(negedge rst_n or posedge clk) //��֡��ʹ���ź�������ȷ�������ض���Ҫ���صĶ˿ڣ���Ŀ�Ķ˿����
    if(!rst_n)
        addr_ram<=  8'd0;
    else if(frame_length_en_ff1&&out_port_num==2'b01)    //enable signal.trigger the flow_control module to work .
        addr_ram<=  addr_reg;//destination port id,RAM read and write address signals.
    else
        addr_ram<=  addr_ram;
//*************************************************************************************************************    



//*************************************************************************************************************    
//�ж��Ƿ���Ҫд��ֵ    
always@(negedge rst_n or posedge clk) //�����ĸ����ڣ���ram2ģ�������дʹ���ź�
    if(!rst_n)
        read_write<=  1'b0;
    else if(rw_en_ff4)
        read_write<=  1'b1;
    else
        read_write<=  1'b0;
//*************************************************************************************************************
//�ȴ��ĸ�����֮�����rw_en
always @(negedge rst_n or posedge clk) //��֡��ʹ��������ȷ��������Ҫ���صĶ˿ڣ�����ʹ���źţ����ڼ�ʱ
    if(!rst_n)
        rw_en<=  1'b0;
    else if(frame_length_en&&out_port_num==2'b01&&!do_not_flow_ctrl) //2010.12.1 MYB//2022/3/3 wzy
        rw_en<=  1'b1;//Used to generate control signals throughout the state transition .
    else
        rw_en<=  1'b0; 
always @(negedge rst_n or posedge clk) //�����ĸ����ں����
begin
    if(!rst_n) begin
        rw_en_ff1<=  1'b0;
        rw_en_ff2<=  1'b0;
        rw_en_ff3<=  1'b0;
        rw_en_ff4<=  1'b0;
    end
    else begin
        rw_en_ff1<=  rw_en;    //In this clock cycle, RAM output data
        rw_en_ff2<=  rw_en_ff1;//In this clock cycle,calculate para. 
        rw_en_ff3<=  rw_en_ff2;//In this clock cycle,compare para with ACimax or Simax to judge   whether the frame can pass the flow control.
        rw_en_ff4<=  rw_en_ff3;//In this clock cycle,write data into RAM and give flow_control result.
    end
end
//*************************************************************************************************************    



//*************************************************************************************************************           		
always @(negedge rst_n or posedge clk) //�����������֡����������Ҫ���صĶ˿�ʱ��Ҳ����һ���źţ����ڼ�ʱ�������result
    if(!rst_n)
        rw_en_h<=  1'b0;
    else if(frame_length_en&&(out_port_num!=2'b01 || do_not_flow_ctrl == 1'b1 )) //2010.12.1 zww
        rw_en_h<=  1'b1;//Used to generate control signals throughout the state transition .
    else
        rw_en_h<=  1'b0; 

always @(negedge rst_n or posedge clk)
    if(!rst_n)
    begin
        rw_en_h_ff1<= 1'b0;
        rw_en_h_ff2<= 1'b0;
        rw_en_h_ff3<= 1'b0;
		rw_en_h_ff4<= 1'b0;
    end
    else
    begin
        rw_en_h_ff1<= rw_en_h;
        rw_en_h_ff2<= rw_en_h_ff1;
        rw_en_h_ff3<= rw_en_h_ff2;
		rw_en_h_ff4<= rw_en_h_ff3;
    end
//*************************************************************************************************************    

//RAM��ȡ�����ݴ���
    reg[31:0] token_data_out_d1 ;
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
            token_data_out_d1 <= 32'd0 ;
        else if(rw_en_ff2)
            token_data_out_d1 <= token_data_out ;
        else 
            token_data_out_d1 <= token_data_out_d1 ;
    end

//*************************************************************************************************************            
always @(negedge rst_n or posedge clk)
begin
	if(!rst_n)
		begin
			token_data_in<=  32'd0;
			flow_result<= 1'b0;
		end
	else if(rw_en_ff3)
		begin
			if(token_data_out_d1[16]==1'b0) //���������ڣ����ؿ���δ������������سɹ�������ram2������Ϣ
				begin
					flow_result<= flow_success ;
					token_data_in<= token_data_out_d1 ;
				end
			else  if(token_data_out_d1[15:0]>=`TOKEN_LOW_LIMIT)//���ؿ������������ҵ�ǰ֡����֮��������������ֵ��������سɹ�����ram2���µ�ǰ������
				begin
					flow_result<= flow_success ;
					token_data_in<= {token_data_out_d1[31:16], (token_data_out_d1[15:0]-{5'd0,frame_length_reg}) } ;
				end
			else 
                begin //������������ǰ֡���󣬲���ͨ�����������ʧ�ܣ�����������
					flow_result<= flow_fail ;
					token_data_in<= token_data_out_d1;
				end			
		end
	else
		begin
			token_data_in<=  token_data_in;
			flow_result<= flow_result ;	
		end
end
//*************************************************************************************************************    



//*************************************************************************************************************    
always @(negedge rst_n or posedge clk) //���ĸ����ڵ��������ؽ��ʹ��Ϊ��Ч
    if(!rst_n)
        result_en<=  1'b0;
    else if (rw_en_ff4||rw_en_h_ff4)
        result_en<=  1'b1;
    else
        result_en<=  1'b0;
        
always @(negedge rst_n or posedge clk) //���ĸ����ڣ�������ؽ��
begin
    if(!rst_n)
        result<=  1'b0;
	else if((out_port_num!=2'b01||do_not_flow_ctrl == 1'b1)&&rw_en_h_ff4) // 2010.12.1  ZWW
	    result<= flow_success;
    else if(rw_en_ff4)
		result<= flow_result ;
    else
        result<=  result;
end

always @(negedge rst_n or posedge clk)//���Ŀ�Ķ˿�
begin
    if(!rst_n)
        des_node_id<=  8'd0;
    else if(addr_en&&!look_fail&&out_port_num==2'b01)
        des_node_id<=  addr;
end
//*************************************************************************************************************    



//*************************************************************************************************************    
//-------------------adding signals "busy" and "operate_addr"--------------------
always @(negedge rst_n or posedge clk) //��Ŀ�ĵ�ַ����֮�������ǰģ��busy��Ҫ������Ŀ�ĵ�ַ�����ĸ����ڹ�������״̬busy=0��
begin
    if(!rst_n)
		begin
			busy<= 1'b0 ;
			operate_addr<= 8'd0 ;
		end
    else if(addr_en&&!look_fail&&out_port_num==2'b01)
		begin
			busy<= 1'b1 ;  
			operate_addr<=  addr;
		end
	else if  (rw_en_ff4)
		begin
			busy<= 1'b0 ;
		    operate_addr<=  8'd0;
		end
	else
		begin
			busy<= busy;
		    operate_addr<=  operate_addr;
		end    
end
//*************************************************************************************************************    

endmodule        

                    
                    
